package com.kevin.util;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @类名: FileUtil
 * @包名：org.xinhua.common.util
 * @时间：2018/5/9 15:49
 * @版本：1.0
 * @描述：文件工具类
 */
public class FileUtil {

    private static final Logger log = LoggerFactory.getLogger(FileUtil.class);

    private FileUtil() {
        // no constructor function
    }

    public static String getFilename(String filepath) {
        int startIndex = filepath.lastIndexOf(File.separator);
        int endIndex = filepath.lastIndexOf(".");
        return filepath.substring(startIndex, endIndex);
    }

    /**
     * 获取文件名的扩展名
     *
     * @param fileName
     * @return
     */
    public static String getExtension(String fileName) {
        String extension = null;
        int index = fileName.lastIndexOf(".");
        if (index > 0) {
            extension = fileName.substring(index + 1);
        }
        return extension == null ? null : extension.toLowerCase();
    }

    /**
     * 写入文件
     *
     * @param is     源字节流
     * @param des    目标文件路径
     * @param append 是否追加
     * @return
     */
    public static void write(InputStream is, String des, boolean append) {
        if (is == null) {
            log.error("源字节流不能为空!");
            return;
        }
        if (StringUtil.isEmpty(des)) {
            log.error("目标文件路径不能为空!");
            return;
        }

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            createDirectories(des);
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(new FileOutputStream(des, append));
            byte[] buf = new byte[4096];
            int len = 0;
            while ((len = bis.read(buf)) != -1) {
                bos.write(buf, 0, len);
            }
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 写入文件
     *
     * @param content 内容
     * @param des     目标文件路径
     * @param append  是否追加
     * @return
     */
    public static void write(String content, String des, boolean append) {
        if (content == null) {
            log.error("内容不能为空!");
            return;
        }
        if (StringUtil.isEmpty(des)) {
            log.error("目标文件路径不能为空!");
            return;
        }

        PrintWriter writer = null;
        try {
            createDirectories(des);
            writer = new PrintWriter(new FileWriter(des, append), true);
            writer.write(content);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 递归创建文件夹
     *
     * @param path
     */
    private static void createDirectories(String path) throws IOException {
        Path des = Paths.get(path);
        if (Files.notExists(des)) {
            Files.createDirectories(des.getParent());
            Files.createFile(des);
        }
    }

    /**
     * 将1GB、5mb类似的文字，转换成文件比较需要的字节数
     *
     * @param sizeStr
     * @return
     */
    public static long convertToBytes(String sizeStr) {
        if (StringUtil.isNotEmpty(sizeStr)) {
            long kb = 1024;
            long mb = kb * 1024;
            long gb = mb * 1024;
            sizeStr = sizeStr.toUpperCase();
            Long sizeDigit = null;

            if (sizeStr.indexOf("GB") > 0 || sizeStr.indexOf("G") > 0) {
                sizeDigit = Long.valueOf(sizeStr.substring(0, (sizeStr.indexOf("GB") > 0 ? sizeStr.indexOf("GB") : sizeStr.indexOf("G"))));
                if (sizeDigit != null && sizeDigit > 0) {
                    return sizeDigit * gb;
                }
            } else if (sizeStr.indexOf("MB") > 0 || sizeStr.indexOf("M") > 0) {
                sizeDigit = Long.valueOf(sizeStr.substring(0, (sizeStr.indexOf("MB") > 0 ? sizeStr.indexOf("MB") : sizeStr.indexOf("M"))));
                if (sizeDigit != null && sizeDigit > 0) {
                    return sizeDigit * mb;
                }
            } else if (sizeStr.indexOf("KB") > 0 || sizeStr.indexOf("K") > 0) {
                sizeDigit = Long.valueOf(sizeStr.substring(0, (sizeStr.indexOf("KB") > 0 ? sizeStr.indexOf("KB") : sizeStr.indexOf("K"))));
                if (sizeDigit != null && sizeDigit > 0) {
                    return sizeDigit * kb;
                }
            } else if (sizeStr.indexOf("B") > 0) {
                return Long.valueOf(sizeStr.substring(0, sizeStr.indexOf("B")));
            }
        }

        return 0L;
    }

    public static String getMd5(String path) throws IOException {
        String md5;
        try (FileInputStream fis = new FileInputStream(path)) {
            md5 = DigestUtils.md2Hex(fis);
        }
        return md5;
    }

    public static String getMD5(String path) throws IOException, NoSuchAlgorithmException {
        String md5;
        long chunkSize = 5 * 1024 * 1024;
        try (FileInputStream fis = new FileInputStream(path)) {
            long size = fis.available();
            md5 = getMD5(0, chunkSize, fis);
            if (fis.available() > chunkSize) {
                md5 = md5 + getMD5(fis.available() - chunkSize, fis.available(), fis);
            } else {
                md5 = md5 + md5;
            }
            md5 = md5 + size;
        }
        return md5;
    }

    public static String getMD5(long start, long end, InputStream inputStream) throws NoSuchAlgorithmException, IOException {
        String strMD5 = "";
        int bufferSize = 256 * 1024;
        byte[] buffer = new byte[bufferSize];
        if (start < 0) {
            start = 0;
        }
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        int len;
        long read = 0;
        int index = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            if (read >= end) {
                break;
            } else {
                if (read + len >= start) {
                    int bStart = 0;
                    if (read != 0 && start - read > 0) {
                        bStart = (int) (start - read);
                    }
                    md5.update(buffer, bStart, len - bStart);
                    index++;
                }
            }
            read = read + len;
        }
        BigInteger bi = new BigInteger(1, md5.digest());
        strMD5 = bi.toString(16);
        strMD5 = String.format("%032d", 0) + strMD5;
        strMD5 = strMD5.substring(strMD5.length() - 32);

        return strMD5;
    }
}